package com.szholly.plug.activity.runtime;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JsonConfig;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.spring.ProcessEngineFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.szholly.plug.activity.model.BpmConfigCache;
import com.szholly.plug.activity.model.BpmConfigRow;
import com.szholly.plug.activity.model.BpmConfigTable;
import com.szholly.plug.activity.model.BpmHistoryRow;
import com.szholly.plug.activity.model.BpmHistoryTable;
import com.szholly.plug.activity.model.BpmTaskConfigRow;
import com.szholly.plug.activity.model.BpmTaskConfigTable;
import com.szholly.plug.activity.model.BpmWorklistRow;
import com.szholly.plug.activity.model.BpmWorklistTable;
import com.szholly.utils.common.json.JsonDateTimeValueProcessor;
import com.szholly.utils.session.SessionFactory;
import com.szholly.utils.session.provider.ISessionProvider;
import com.szholly.utils.util.DateUtil;
import com.szholly.utils.util.StringUtils;
import com.szholly.data.general.GlobalDataType;
import com.szholly.data.general.IQueryMap;
import com.szholly.data.general.PageInfo;
import com.szholly.data.general.QueryMap;
import com.szholly.data.general.RowBase;
import com.szholly.plug.safe.entity.user.UserEntity;

/**
 * 定义工作流对外操作控制器
 */
@Controller
@RequestMapping(value = "/workflow")
public class BpmController {

	protected Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired(required = false)
	protected RepositoryService repositoryService;
	@Autowired(required = false)
	protected RuntimeService runtimeService;
	@Autowired(required = false)
	protected ProcessEngineFactoryBean processEngine;
	/**
	 * 流程任务服务
	 */
	@Autowired(required = false)
	protected TaskService taskService;
	/**
	 * 流程历史服务
	 */
	@Autowired(required = false)
	protected HistoryService historyService;

	/**
	 * 
	 * @param executionId
	 *            运行实例ID
	 * @param pDefinitionId
	 *            流程定义ID
	 * @param response
	 */
	@RequestMapping(value = "/exeimage")
	public void viewCurrentImage(
			@RequestParam("executionId") String executionId,
			@RequestParam("definitionId") String pDefinitionId,
			HttpServletResponse response) {

		ProcessInstance processInstance = runtimeService
				.createProcessInstanceQuery().processInstanceId(executionId)
				.singleResult();
		if (processInstance != null) {
			getExeImage(executionId, response, processInstance);
		} else {
			getDefinitionImage(pDefinitionId, response);
		}
	}

	/**
	 * 生成流程定义图片
	 * 
	 * @param executionId
	 * @param response
	 * @param processInstance
	 */
	private void getDefinitionImage(String pDefinitionId,
			HttpServletResponse response) {

		ProcessDefinition processDefinition = repositoryService
				.createProcessDefinitionQuery()
				.processDefinitionKey(pDefinitionId).latestVersion()
				.singleResult();
		String diagramResourceName = processDefinition.getDiagramResourceName();
		InputStream imageStream = repositoryService.getResourceAsStream(
				processDefinition.getDeploymentId(), diagramResourceName);

		// 输出资源内容到相应对象
		byte[] b = new byte[1024];
		int len;
		try {
			OutputStream stream = response.getOutputStream();
			while ((len = imageStream.read(b, 0, 1024)) != -1) {
				stream.write(b, 0, len);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 生成流程实例图片
	 * 
	 * @param executionId
	 * @param response
	 * @param processInstance
	 */
	private void getExeImage(String executionId, HttpServletResponse response,
			ProcessInstance processInstance) {
		BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance
				.getProcessDefinitionId());
		List<String> activeActivityIds = runtimeService
				.getActiveActivityIds(executionId);
		// 使用spring注入引擎请使用下面的这行代码
		Context.setProcessEngineConfiguration(processEngine
				.getProcessEngineConfiguration());
		List<String> nullList = new ArrayList<String>();
		InputStream imageStream = processEngine
				.getProcessEngineConfiguration()
				.getProcessDiagramGenerator()
				.generateDiagram(
						bpmnModel,
						"png",
						activeActivityIds,
						nullList,
						processEngine.getProcessEngineConfiguration()
								.getActivityFontName(),
						processEngine.getProcessEngineConfiguration()
								.getLabelFontName(),
						processEngine.getProcessEngineConfiguration()
								.getClassLoader(), 1.0);

		// 输出资源内容到相应对象
		byte[] b = new byte[1024];
		int len;
		try {
			OutputStream stream = response.getOutputStream();
			while ((len = imageStream.read(b, 0, 1024)) != -1) {
				stream.write(b, 0, len);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取历史信息
	 * 
	 * @param executionId
	 * @param response
	 */
	@RequestMapping(value = "/history")
	public void getHistory(@RequestParam("executionId") String executionId,
			HttpServletResponse response) {
		IQueryMap queryMap = new QueryMap();
		queryMap.getWhereMap().put(BpmHistoryRow.FIELD_SExeid, executionId);
		queryMap.getOrderByMap().put(BpmHistoryRow.FIELD_SOptiontime, 1);
		List<RowBase> rows = BpmHistoryTable.getSingleRef().getEntityList(
				RowBase.class, queryMap);
		if (rows == null) {
			return;
		}

		JsonConfig jsonConfig = new JsonConfig();
		jsonConfig.registerJsonValueProcessor(Date.class,
				new JsonDateTimeValueProcessor());
		JSONArray arrayObject = JSONArray.fromObject(rows, jsonConfig);
		String returnValue = arrayObject.toString();
		// 向浏览器发送一个响应头，设置浏览器的解码方式为UTF-8
		response.setHeader("Content-type", "text/html;charset=UTF-8");
		OutputStream stream;
		try {
			stream = response.getOutputStream();
			stream.write(returnValue.getBytes("UTF-8"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取任务节点的配置信息
	 * 
	 * @param pDefinitionId
	 * @param taskId
	 * @param response
	 */
	@RequestMapping(value = "/form")
	public void getFormConfig(
			@RequestParam("definitionId") String pDefinitionId,
			@RequestParam("taskId") String taskId, HttpServletResponse response) {
		BpmTaskConfigRow row = BpmConfigCache.getTaskConfig(pDefinitionId,
				taskId);
		if (row == null) {
			return;
		}
		
		String fromConfig = "";
		String optionField = row.getTJ();
		if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
			fromConfig += "\"tj\":true,";
		}
		optionField = row.getTH();
		if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
			fromConfig += "\"th\":true,";
		}
		optionField = row.getCX();
		if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
			fromConfig += "\"cx\":true,";
		}
		optionField = row.getCH();
		if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
			fromConfig += "\"ch\":true,";
		}
		optionField = row.getJB();
		if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
			fromConfig += "\"jb\":true,";
		}
		optionField = row.getBC();
		if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
			fromConfig += "\"bc\":true,";
		}
		optionField = row.getLCT();
		if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
			fromConfig += "\"lct\":true,";
		}
		optionField = row.getTabs();
		if(!StringUtils.IsNullOrSpace(optionField)){
			fromConfig += "\"_showTab\":\""+optionField+"\",";
		}
		
		if(!StringUtils.IsNullOrSpace(fromConfig)){
			optionField = row.getSFormconfig();
			if (!StringUtils.IsNullOrSpace(optionField)) {
				fromConfig += optionField;
			} else {
				fromConfig = fromConfig.substring(0, fromConfig.length()-1);
			}
		} else {
			optionField = row.getSFormconfig();
			fromConfig = optionField;
		}
		if(StringUtils.IsNullOrSpace(fromConfig)){
			return;
		}
		
		fromConfig = "{" + fromConfig + "}";
		// 向浏览器发送一个响应头，设置浏览器的解码方式为UTF-8
		response.setHeader("Content-type", "text/html;charset=UTF-8");
		OutputStream stream;
		try {
			stream = response.getOutputStream();
			stream.write(fromConfig.getBytes("UTF-8"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取任务节点的配置信息
	 * 
	 * @param pDefinitionId
	 * @param response
	 */
	@RequestMapping(value = "/forms")
	public void getFormsConfig(
			@RequestParam("definitionId") String pDefinitionId,
			HttpServletResponse response) {
		Map<String, BpmTaskConfigRow> rows = BpmConfigCache
				.getTasksConfig(pDefinitionId);
		if (rows == null) {
			return;
		}

		String returnValue = "";
		Set<String> keys = rows.keySet();
		for (String key : keys) {
			BpmTaskConfigRow row = rows.get(key);
			String fromConfig = "";
			String optionField = row.getTJ();
			if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
				fromConfig += "\"tj\":true,";
			}
			optionField = row.getTH();
			if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
				fromConfig += "\"th\":true,";
			}
			optionField = row.getCX();
			if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
				fromConfig += "\"cx\":true,";
			}
			optionField = row.getCH();
			if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
				fromConfig += "\"ch\":true,";
			}
			optionField = row.getJB();
			if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
				fromConfig += "\"jb\":true,";
			}
			optionField = row.getBC();
			if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
				fromConfig += "\"bc\":true,";
			}
			optionField = row.getLCT();
			if(!StringUtils.IsNullOrSpace(optionField) && optionField.equals("1")){
				fromConfig += "\"lct\":true,";
			}
			optionField = row.getTabs();
			if(!StringUtils.IsNullOrSpace(optionField)){
				fromConfig += "\"_showTab\":\""+optionField+"\",";
			}
			
			if(!StringUtils.IsNullOrSpace(fromConfig)){
				optionField = row.getSFormconfig();
				if (!StringUtils.IsNullOrSpace(optionField)) {
					//mysql导入oracle数据库时配置数据中的"号丢失  
					//将配置信息的引号替换为空 再重新加上 
					String [] optionArr = optionField.split(",");
					for(String option : optionArr){
						if(!StringUtils.IsNullOrSpace(option)){
							fromConfig += "\""+option.split(":")[0].replaceAll("\"", "")+"\":"+option.split(":")[1]+",";
						}
					}
					//fromConfig += optionField;
				}
				
				fromConfig = fromConfig.substring(0, fromConfig.length()-1);
			} else {
				optionField = row.getSFormconfig();
				fromConfig = optionField;
			}
			
			if (StringUtils.IsNullOrSpace(fromConfig)) {
				continue;
			}

			returnValue += "\"" + key + "\":" + "{" + fromConfig + "},";
		}
		if (returnValue != "") {
			returnValue = returnValue.substring(0, returnValue.length() - 1);
			returnValue = "{" + returnValue + "}";
		}

		// 向浏览器发送一个响应头，设置浏览器的解码方式为UTF-8
		response.setHeader("Content-type", "text/html;charset=UTF-8");
		OutputStream stream;
		try {
			stream = response.getOutputStream();
			stream.write(returnValue.getBytes("UTF-8"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获得待办任务列表
	 * 
	 * @param pageNo
	 * @param pageSize
	 * @param candidateUser
	 * @param pDefId
	 * @param taskId
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@RequestMapping(value = "/worklist")
	public void getWorkList(@RequestParam("queryData") String query,
			@RequestParam("orderData") String order,
			@RequestParam("pageSizeData") int pageSize,
			@RequestParam("pageIndexData") int pageIndex,
			@RequestParam("getAllCount") boolean getAllCount,
			@RequestParam("refresRowCount") boolean refresRowCount,
			HttpServletResponse response) {
		// 获取查询条件
		JSONObject queryJsonObject = JSONObject.fromObject(query);
		HashMap<String, Object> whereMap = (HashMap<String, Object>) JSONObject
				.toBean(queryJsonObject, HashMap.class);

		// 获取排序条件
		JSONObject orderJsonObject = JSONObject.fromObject(order);
		HashMap<String, Object> orderMap = (HashMap<String, Object>) JSONObject
				.toBean(orderJsonObject, HashMap.class);

		IQueryMap queryMap = new QueryMap();
		queryMap.setAddCaptionField(true);
		queryMap.setWhereMap(whereMap);
		queryMap.setOrderByMap(orderMap);
		PageInfo pageInfo = new PageInfo();
		pageInfo.setPageIndex(pageIndex);
		pageInfo.setPageSize(pageSize);
		pageInfo.setRefreshRowCount(refresRowCount);

		ISessionProvider session = SessionFactory.getSession();
		UserEntity userEntity = (UserEntity) session
				.getObject(ISessionProvider.UserEntity);
		if (userEntity != null && !userEntity.getIsSuperAdmin()) {
			queryMap.getWhereMap().put(
					BpmWorklistRow.FIELD_SAssingusers + ":like",
					userEntity.getUserID());
		}

		JsonConfig jsonConfig = new JsonConfig();
		jsonConfig.registerJsonValueProcessor(Date.class,
				new JsonDateTimeValueProcessor());

		List<RowBase> rows = BpmWorklistTable.getSingleRef().pageSelect(
				RowBase.class, queryMap, pageInfo);
		HashMap<String, Object> worklistInfo = new HashMap<String, Object>();
		if (getAllCount) {
			queryMap = new QueryMap();
			queryMap.setSelectFields("count(1)");
			if (userEntity != null && !userEntity.getIsSuperAdmin()) {
				queryMap.getWhereMap().put(
						BpmWorklistRow.FIELD_SAssingusers + ":like",
						userEntity.getUserID());
			}
			Object max = BpmWorklistTable.getSingleRef().getExecuteScalar(
					queryMap);
			if (max != null) {
				String maxString = max.toString();
				int maxInt = Integer.parseInt(maxString);
				worklistInfo.put("ALLROWCOUNT", maxInt);
			}
		}

		if (rows != null && rows.size() > 0) {
			// 处理等待时间
			for (RowBase row : rows) {
				Date beginTime = (Date) row.getValue(GlobalDataType.DateTime,
						BpmWorklistRow.FIELD_DBegintime);
				Long day = DateUtil.getDiffDayEx(beginTime);
				if (day > 0) {
					row.setValue("wait_day", day);
					row.setValue("wait_title", "天");
				} else {
					day = DateUtil.getDiffDayEx2(beginTime);
					if (day > 0) {
						row.setValue("wait_day", day);
						row.setValue("wait_title", "小时");
					} else {
						day = DateUtil.getDiffDayEx3(beginTime);
						if (day > 0) {
							row.setValue("wait_day", day);
							row.setValue("wait_title", "分钟");
						} else {
							day = DateUtil.getDiffDayEx4(beginTime);
							if (day >= 0) {
								row.setValue("wait_day", day);
								row.setValue("wait_title", "秒");
							}
						}
					}
				}
			}

			worklistInfo.put("ROWCOUNT", pageInfo.getRowCount());
			worklistInfo.put("PAGECOUNT", pageInfo.getPageCount());
			worklistInfo.put("WORKLIST", rows);
		} else {
			worklistInfo.put("ROWCOUNT", -1);
			worklistInfo.put("PAGECOUNT", 1);
			worklistInfo.put("WORKLIST", null);
		}

		JSONObject jsonObject = JSONObject.fromObject(worklistInfo, jsonConfig);
		String returnValue = jsonObject.toString();

		// 向浏览器发送一个响应头，设置浏览器的解码方式为UTF-8
		response.setHeader("Content-type", "text/html;charset=UTF-8");
		OutputStream stream;
		try {
			stream = response.getOutputStream();
			stream.write(returnValue.getBytes("UTF-8"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 自动保存
	 * @param processDefinitionId
	 */
	@RequestMapping(value = "/autoSaveTask")
	public void autoSaveTaskConfig(@RequestParam("processDefinitionId") String procInstId, 
			HttpServletResponse response) {
		
		ProcessDefinition processDefinition = repositoryService
				.createProcessDefinitionQuery()
				.processDefinitionKey(procInstId).latestVersion()
				.singleResult();
		
		BpmConfigRow row = new BpmConfigRow();
		row.setBusiness("");
		HashMap<String, List<RowBase>> childs = new HashMap<String, List<RowBase>>();
		List<RowBase> childList = new ArrayList<RowBase>();
		childs.put(BpmTaskConfigTable.TABLE_NAME, childList);
		row.setChildValues(childs);
		row.setSDefitionid(procInstId);
		row.setSDefitionName(processDefinition.getName());
		row.setSFormurl("");
		row.setSFormvalue("");
		row.setSGroup(procInstId);
		
		BpmTaskConfigRow taskConfig = new BpmTaskConfigRow();
		taskConfig.setSTaskid("U0");
		taskConfig.setTaskCanDel("1");
		taskConfig.setTaskName("开始");
		taskConfig.setOrder("0");
		taskConfig.setNNextPress("${S_OPTION==\"退回\"}");
		taskConfig.setTJ("1");
		taskConfig.setTH("0");
		taskConfig.setCX("0");
		taskConfig.setCH("0");
		taskConfig.setJB("0");
		taskConfig.setBC("1");
		taskConfig.setLCT("0");
		
		taskConfig.setNoticeJbmb("{TaskUser}在{TaskTime}已经处理了您的“{BpmGroupName}-{TaskTitle}”业务，流程节点{TaskDefinitionName}，处理结果{TaskResult}。");
		taskConfig.setNoticeDbmb("您有一条业务“{BpmGroupName}-{TaskTitle}”需要处理，处理到期时间：{TaskEndTime}。");
		taskConfig.setNoticeLsrmb("{TaskUser}在{TaskTime}已经处理了您的“{BpmGroupName}-{TaskTitle}”业务，流程节点{TaskDefinitionName}，处理结果{TaskResult}。");
		taskConfig.setRemindersMb("您有一条业务“{BpmGroupName}-{TaskTitle}”需要处理，处理到期时间：{TaskEndTime}。");
		
		childList.add(taskConfig);
		
		Integer i = 1;
		ProcessDefinitionEntity def = (ProcessDefinitionEntity)((RepositoryServiceImpl)
				repositoryService).getDeployedProcessDefinition(processDefinition.getId());  
        List<ActivityImpl> activitiList = def.getActivities();
		for(ActivityImpl impl : activitiList){
			String typeString = (String)impl.getProperty("type");
			if ("userTask".equals(typeString)){
				taskConfig = new BpmTaskConfigRow();
				taskConfig.setSTaskid(impl.getId());
				taskConfig.setTaskName((String)impl.getProperty("name"));
				taskConfig.setOrder(i.toString());
				taskConfig.setNNextPress("${S_OPTION==\"退回\"}");
				taskConfig.setNoticeJbmb("{TaskUser}在{TaskTime}已经处理了您的“{BpmGroupName}-{TaskTitle}”业务，流程节点{TaskDefinitionName}，处理结果{TaskResult}。");
				taskConfig.setNoticeDbmb("您有一条业务“{BpmGroupName}-{TaskTitle}”需要处理，处理到期时间：{TaskEndTime}。");
				taskConfig.setNoticeLsrmb("{TaskUser}在{TaskTime}已经处理了您的“{BpmGroupName}-{TaskTitle}”业务，流程节点{TaskDefinitionName}，处理结果{TaskResult}。");
				taskConfig.setRemindersMb("您有一条业务“{BpmGroupName}-{TaskTitle}”需要处理，处理到期时间：{TaskEndTime}。");
				
				if(i==1){
					taskConfig.setTaskCanDel("1");
					taskConfig.setTJ("1");
					taskConfig.setTH("0");
					taskConfig.setCX("1");
					taskConfig.setCH("0");
					taskConfig.setJB("1");
					taskConfig.setBC("1");
					taskConfig.setLCT("1");
				}else{
					taskConfig.setTaskCanDel("0");
					taskConfig.setTJ("1");
					taskConfig.setTH("1");
					taskConfig.setCX("1");
					taskConfig.setCH("1");
					taskConfig.setJB("1");
					taskConfig.setBC("1");
					taskConfig.setLCT("1");
				}
				i++;
				childList.add(taskConfig);
			}
		}
		
		taskConfig = new BpmTaskConfigRow();
		taskConfig.setSTaskid("U9");
		taskConfig.setTaskCanDel("1");
		taskConfig.setTaskName("结束");
		taskConfig.setOrder(i.toString());
		taskConfig.setNNextPress("${S_OPTION==\"退回\"}");
		taskConfig.setTJ("0");
		taskConfig.setTH("0");
		taskConfig.setCX("0");
		taskConfig.setCH("0");
		taskConfig.setJB("0");
		taskConfig.setBC("0");
		taskConfig.setLCT("1");
		taskConfig.setNoticeJbmb("{TaskUser}在{TaskTime}已经处理了您的“{BpmGroupName}-{TaskTitle}”业务，流程节点{TaskDefinitionName}，处理结果{TaskResult}。");
		taskConfig.setNoticeDbmb("您有一条业务“{BpmGroupName}-{TaskTitle}”需要处理，处理到期时间：{TaskEndTime}。");
		taskConfig.setNoticeLsrmb("{TaskUser}在{TaskTime}已经处理了您的“{BpmGroupName}-{TaskTitle}”业务，流程节点{TaskDefinitionName}，处理结果{TaskResult}。");
		taskConfig.setRemindersMb("您有一条业务“{BpmGroupName}-{TaskTitle}”需要处理，处理到期时间：{TaskEndTime}。");
		childList.add(taskConfig);
		
		BpmConfigTable.getSingleRef().save(row);
		
		JSONObject jsonObejct = JSONObject.fromObject(row);
		String returnValue = jsonObejct.toString();
		response.setHeader("Content-type", "text/html;charset=UTF-8");
		OutputStream stream;
		try {
			stream = response.getOutputStream();
			stream.write(returnValue.getBytes("UTF-8"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}